<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button id="btn1">11111111</button>
    <script>
      const bucket = new WeakMap();
      const data = {foo:1}
      const effectStack = [];
      let activeEffect;
      function effect(fn, options) {
        const effectFn = () => {
          cleanup(effectFn);
          activeEffect = effectFn;
          effectStack.push(effectFn)
          fn();
          effectStack.pop();
          activeEffect = effectStack[effectStack.length-1]
        };
        effectFn.options = options;
        effectFn.deps = [];
        effectFn();
      }
      const obj = new Proxy(data, {
        get(target, key) {
          console.log("get", key);
          track(target, key);
          return target[key];
        },
        set(target, key, newVal) {
          console.log("set", key);
          target[key] = newVal;
          trigger(target, key);
        },
      });
      function track(target, key) {
        if (!activeEffect) return;
        let depsMap = bucket.get(target);
        if (!depsMap) {
          bucket.set(target, (depsMap = new Map()));
        }
        let deps = depsMap.get(key);
        if (!deps) {
          depsMap.set(key, (deps = new Set()));
        }
        deps.add(activeEffect);
        activeEffect.deps.push(deps);
      }

      function trigger(target, key) {
        const depsMap = bucket.get(target);
        if (!depsMap) return;
        const effects = depsMap.get(key);
        const effectsToRun = new Set();
        effects && effects.forEach(effectFn=>{
          if(effectFn !== activeEffect){
            effectsToRun.add(effectFn);
          }
        });
        effectsToRun.forEach(effectFn=>{
          if(effectFn.options.scheduler){
            effectFn.options.scheduler(effectFn);
          } else {
            effectFn();
          }
        });
      }

      function cleanup(effectFn) {
        for (let i = 0; i < effectFn.deps.length; i++) {
          const deps = effectFn.deps[i];
          deps.delete(effectFn);
        }
        effectFn.deps.length = 0;
      }

      effect(function effectFn() {
        console.log(obj.foo)
      },{
        scheduler(fn){
          setTimeout(fn)
        }
      });
      obj.foo++;
      console.log("结束了")
     
    </script>
  </body>
</html>
